/*
 * Copyright (C) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (C) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.loader;

import java.util.ArrayList;

import android.database.Cursor;

import id.duapuluhdua.dakidaki.common.CommonActivity;
import id.duapuluhdua.dakidaki.data.common.Database;
import id.duapuluhdua.dakidaki.data.items.DataItemTrack;
import id.duapuluhdua.dakidaki.data.tables.DataTableGeoPoints;
import id.duapuluhdua.dakidaki.data.tables.DataTableGeoPoints.column;
import id.duapuluhdua.dakidaki.layers.LayerTrack;
import id.duapuluhdua.dakidaki.map.GeoPoint;
import id.duapuluhdua.dakidaki.map.Mercator;
import id.duapuluhdua.dakidaki.map.Screen;

/**
 *
 */
public class TrackItem extends LoaderItem
{
  /** Fields */
  private LayerTrack mLayer;

  public DataItemTrack dataTrack;
  public ArrayList<GeoPoint> vecTrackPoint;

  private boolean bPointsAlreadyLoaded = false;

  /**
   * @param parent
   * @param screen
   * @param database
   * @param itemId
   */
  public TrackItem(CommonActivity parent, Screen screen, Database database, long itemId)
  {
    super(parent, screen, database, itemId);

    vecTrackPoint = new ArrayList<GeoPoint>();
    mLayer = new LayerTrack(parent, screen, this);
  }

  /**
   * Reloads the position points of the current track.
   */
  @Override
  public boolean reload()
  {
    dataTrack = mDatabase.getTableTracks().getTrackItem(getId());
    if (dataTrack != null) {
      // Always reload points of open track.
      if (!bPointsAlreadyLoaded) {
        loadPoints();
        bPointsAlreadyLoaded = dataTrack.isClosed();
      }
      return true;
    }
    return false;
  }

  /**
   * Retrieves the position points from the database and loads them to the
   * current track-point list.
   */
  private void loadPoints()
  {
    final DataTableGeoPoints table = mDatabase.getTableGeoPoints();
    final String where = String.format("%s = %d", table.getColumnName(column.TrackID), getId());

    synchronized(vecTrackPoint)
    {
      vecTrackPoint.clear();
    }

    addPoints(where);
  }

  /* Encapsulates the query result in the Cursor object as GeoPoint objects
   * and supplies them with the coordinate (X, Y) for map drawing. */
  private void addPoints(String where)
  {
    final DataTableGeoPoints table = mDatabase.getTableGeoPoints();
    final String orderBy = table.getColumnName(column.ID) + " ASC";
    final Cursor cr = table.getDataRecords(where, orderBy);

    if (cr != null) {
      while (!cr.isAfterLast()) {
        final GeoPoint geoPoint = new GeoPoint(cr);
        synchronized(vecTrackPoint)
        {
          vecTrackPoint.add(geoPoint);
        }
        cr.moveToNext();
      }
      cr.close();
    }

    // Prepare data before the drawing
    synchronized(vecTrackPoint)
    {
      if (!vecTrackPoint.isEmpty()) {
        Mercator.convertToFlat(vecTrackPoint);
      }
    }
  }

  /**
   * @return
   */
  public boolean isClosed()
  {
    return dataTrack.isClosed();
  }

  /**
   *
   * @return
   */
  public boolean isRecording()
  {
    // If a track record is NOT closed means it is still recording.
    return !dataTrack.isClosed();
  }

  @Override
  public boolean isSelected()
  {
    return (mState.getSelectedTrack() == getId());
  }

  @Override
  public LayerTrack getLayer()
  {
    return mLayer;
  }

  /**
   * Gets the track description that contains the track name and the total
   * distance.
   */
  @Override
  public String getDescription()
  {
    String text = "";

    updateTotalDistance();

    text += dataTrack.getName();
    text += " - ";
    text += dataTrack.getDistanceAsString(mPreference);

    return text;
  }

  /**
   * Checks whether the track has tracking points.
   *
   * @return true if there is no tracking points, or false otherwise.
   */
  public boolean isEmpty()
  {
    boolean bValue = false;
    synchronized(vecTrackPoint)
    {
      bValue = vecTrackPoint.isEmpty();
    }
    return bValue;
  }

  /**
   *
   */
  private void updateTotalDistance()
  {
    dataTrack.setDistance(getTotalDistanceInMeters());
  }

  /**
   * @return
   */
  public double getTotalDistanceInMeters()
  {
    double totalDistance = 0;

    synchronized(vecTrackPoint)
    {
      GeoPoint lastGeoPoint = null;

      for (GeoPoint point : vecTrackPoint) {
        if (lastGeoPoint != null) {
          totalDistance += point.distance(lastGeoPoint);
        }
        lastGeoPoint = point;
      }
    }
    return totalDistance;
  }

  public ArrayList<GeoPoint> clonePoints()
  {
    ArrayList<GeoPoint> pointsCopy = new ArrayList<GeoPoint>();
    synchronized(vecTrackPoint)
    {
      pointsCopy.addAll(vecTrackPoint);
    }
    return pointsCopy;
  }
}
